using GoodroommateComputingPlatform.Algorithms.BackPropagationDeep;
using GoodroommateComputingPlatform.Models.Goodroommate;
using System;
using System.Linq;
using Newtonsoft.Json;
using GoodroommateComputingPlatform.Models;
using Microsoft.Extensions.Options;
using System.IO;
using System.Text;

namespace GoodroommateComputingPlatform.Tasks.Goodroommate
{
    public class BackPropagationDeepTasks
    {

        private ITaskManager _tm;
        private GoodroomDbContext _context;
        private UserContentsPathOption _userContents;

        public const string TaskOfBackPropagationDeep = "gr-BackPropagationDeep";
        public const string TaskOfSaveWeight = "gr-BackPropagationDeep";

        public const string KeyOfBackPropagationDeepStartDateTime = "computing.gr-BackPropagationDeep.starttime.local";
        public const string KeyOfBackPropagationDeepCompleteDateTime = "computing.gr-BackPropagationDeep.completetime.local";
        
        public BackPropagationDeepTasks(ITaskManager tm, GoodroomDbContext context, IOptions<UserContentsPathOption> userContents)
        {
            _tm = tm;
            _context = context;
            _userContents = userContents.Value;

            tm.RegisterTask(TaskOfBackPropagationDeep, BackPropagationDeepProcess, this);
        }


        private static object BackPropagationDeepProcess(object globls, object state)
        {
            var self = (BackPropagationDeepTasks)globls;
            
            WriteDateTime(self._context, KeyOfBackPropagationDeepStartDateTime);

            try
            {
                DoBackPropagationDeep(self._context, self._userContents);
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                WriteDateTime(self._context, KeyOfBackPropagationDeepCompleteDateTime);
            }
            
            return null;
        }

        
        private static int WriteDateTime(GoodroomDbContext context, string key)
        {
            var tk = context.keydata.Where(k => k.Key == key);
            if (tk.Count() > 0)
                tk.First().Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            else
                context.keydata.Add(new KeyData()
                {
                    Key = key,
                    Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                });
            return context.SaveChanges();
        }

        private static void DoBackPropagationDeep(GoodroomDbContext context, UserContentsPathOption _userContents)
        {
             // 获取数据
            var dataset = from domitorypreference in context.domitorypreference
                          select new DomitoryPreference()
                          {                       
                            UserID =domitorypreference.UserID,
                            DomitoryCount =domitorypreference.DomitoryCount,
                            DomitoryNoisy =domitorypreference.DomitoryNoisy,
                            DomitoryLayer =domitorypreference.DomitoryLayer,
                            DomitoryYear =domitorypreference.DomitoryYear,
                            DomitoryTag =domitorypreference.DomitoryTag,
                          };
            var list = dataset.ToArray();

            //训练
            var bpdeep = new BackPropagationDeep(new int[] { 4, 20, 1 }, 0.15, 0.8);
            for (int i = 0; i < 5000; i++)
            {
                for (int j = 0; j < list.Length; j++)
                    bpdeep.Train(new double[] { list[j].DomitoryCount, list[j].DomitoryNoisy, list[j].DomitoryLayer, list[j].DomitoryYear }, new double[] { list[j].DomitoryTag });
            }

            // 存储学习结果
            string userContentsPath = _userContents.Goodroommate;
            string bpmodelPath = Path.Combine(userContentsPath, "model", "bpmodel.json");
            using (var fs = new FileStream(bpmodelPath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                using (var sw = new StreamWriter(fs, new UTF8Encoding(false)))
                {
                    sw.Write(JsonConvert.SerializeObject(bpdeep));
                }
            }
        }
    }
}